<?php
namespace control;

include_once "errorCode.php";

class PKCS7Encoder
{
    public static int $block_size = 32;

    public function encode($text)
    {
        $block_size = PKCS7Encoder::$block_size;
        $text_length = strlen($text);
        $amount_to_pad = PKCS7Encoder::$block_size - ($text_length % PKCS7Encoder::$block_size);
        if ($amount_to_pad == 0) {
            $amount_to_pad = PKCS7Encoder::$block_size;
        }
        $pad_chr = chr($amount_to_pad);
        $tmp = "";
        for ($index = 0; $index < $amount_to_pad; $index++) {
            $tmp .= $pad_chr;
        }
        return $text . $tmp;
    }

    public function decode($text)
    {
        $pad = ord(substr($text, -1));
        if ($pad < 1 || $pad > PKCS7Encoder::$block_size) {
            $pad = 0;
        }
        return substr($text, 0, (strlen($text) - $pad));
    }
}

class Prpcrypt
{
    public string $key;
    public function __construct($k)
    {
        $this->key = base64_decode($k . "=");        //为变量赋值
    }

    /*  function Prpcrypt($k)
      {
        $this->key = base64_decode($k . "=");
      }*/
    public function encrypt($text, $corpid)
    {
        try {
            //获得16位随机字符串，填充到明文之前
            $random = $this->getRandomStr();
            $text = $random . pack("N", strlen($text)) . $text . $corpid;
            // 网络字节序
            $version = substr(PHP_VERSION, 0, 3);
            if ($version < '7.1') {//(PHP 4, PHP 5 正常使用) （php6-php7.0 可能会warning提示但是屏蔽错误后可继续使用）（php7.1+ 由openssl_encrypt替代）

                // mcrypt 函数在php7.1 以上版本被遗弃，可使用替代函数。。。 这里以@屏蔽错误，  @的使用会影响效率
                @$size = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);//mcrypt_get_block_size() 用来获取 cipher （其中包括了加密模式） 加密算法分组大小。
                @$module = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');/// 打开加密算法和模式
                $iv = substr($this->key, 0, 16);
                //使用自定义的填充方式对明文进行补位填充
                $pkc_encoder = new PKCS7Encoder;
                $text = $pkc_encoder->encode($text);
                @mcrypt_generic_init($module, $this->key, $iv);//mcrypt_generic_init — 初始化加密所需的缓冲区  在每次调用 mcrypt_generic() 或 mdecrypt_generic() 函数之前必须调用本函数。
                //加密
                @$encrypted = mcrypt_generic($module, $text);//本函数用来加密数据。 传入数据长度必须是 n * 分组大小，否则需要后补 "\0"。 本函数返回加密后的数据。 注意，根据数据补齐不同， 返回的数据可能比输入的数据长度有所增加。
                //$moudle为加密描述符，$text为加密前的数据，数据加密函数返回加密后的字符串

                @mcrypt_generic_deinit($module);//mcrypt_generic_deinit — 对加密模块进行清理工作   它会清理缓冲区，但是并不关闭模块。 要想关闭加密模块， 你需要自行调用 mcrypt_module_close() 函数。
                @mcrypt_module_close($module);
                //print(base64_encode($encrypted));
                //使用BASE64对加密后的字符串进行编码

            } else {
                //php 7.1  //echo base64_encode(openssl_encrypt($str, 'aes-128-cbc', $key, true, $iv));
                //    $data = openssl_encrypt($text, 'aes-128-cbc',$this->key,true,$iv);
                //   $encrypted = $data;
                $iv = substr($this->key, 0, 16);
                $aes_encrypt = openssl_encrypt($text, 'AES-256-CBC', $this->key, OPENSSL_RAW_DATA, $iv);
                //  $msg_encrypt =base64_encode($aes_encrypt);
                $encrypted = $aes_encrypt;
                //return $data;
                //php 7.1

            }


            return array(ErrorCode::$OK, base64_encode($encrypted));
        } catch (Exception $e) {
            print $e;
            return array(ErrorCode::$EncryptAESError, null);
        }
    }

    public function decrypt($encrypted, $corpid)
    {
        try {
            $ciphertext_dec = base64_decode($encrypted);
            $iv = substr($this->key, 0, 16);
            $version = substr(PHP_VERSION, 0, 3);
            if ($version < '7.1') {
                @$module = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');

                @mcrypt_generic_init($module, $this->key, $iv);
                @$decrypted = mdecrypt_generic($module, $ciphertext_dec);
                @mcrypt_generic_deinit($module);
                @mcrypt_module_close($module);
            } else {

                ///php7.1 jiemi

                //echo openssl_decrypt(base64_decode($strEncode), 'aes-128-cbc', $key, true, $iv);
                //$decrypted = openssl_decrypt($ciphertext_dec, 'AES-256-CBC',$this->key, OPENSSL_RAW_DATA, $iv);//使用OPENSSL_RAW_DATA不行
                $decrypted = openssl_decrypt($encrypted, 'AES-256-CBC', $this->key, OPENSSL_ZERO_PADDING, $iv);//注意openssl_decrypt第一个参数是base64加密过的字符串，第四个参数是OPENSSL_ZERO_PADDING不是上面加密时的 OPENSSL_RAW_DATA
                //  $decrypted .='xx';
                ///php7.1 jiemi

            }


        } catch (Exception $e) {
            return array(ErrorCode::$DecryptAESError, null);
        }
        try {
            //去除补位字符
            $pkc_encoder = new PKCS7Encoder();
            $result = $pkc_encoder->decode($decrypted);
            //去除16位随机字符串,网络字节序和AppId
            if (strlen($result) < 16)
                return "";
            $content = substr($result, 16, strlen($result));
            $len_list = unpack("N", substr($content, 0, 4));
            $xml_len = $len_list[1];
            $xml_content = substr($content, 4, $xml_len);
            $from_corpid = substr($content, $xml_len + 4);
        } catch (Exception $e) {
            print $e;
            return array(ErrorCode::$DecryptAESError, null);
        }
        if ($from_corpid != $corpid)
            return array(ErrorCode::$ValidateSuiteKeyError, null);
        return array(0, $xml_content);
    }

    function getRandomStr()
    {
        $str = "";
        $str_pol = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
        $max = strlen($str_pol) - 1;
        for ($i = 0; $i < 16; $i++) {
            $str .= $str_pol[mt_rand(0, $max)];
        }
        return $str;
    }
}